﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Xunit;
using Rhino.Mocks;
using ValidationFramework.Facts.Research.Fakes;

namespace ValidationFramework.Facts.Research
{
	public class ValidationManagerFacts
	{
		// --- Internal Classes
		public class Person
		{
			public string Name { get; set; }
			public string NickName { get; set; }
			public int Awesomeness { get; set; }
		}

		// --- Constructor
		public ValidationManagerFacts()
		{

		}

		public class On_Construction
		{
			// --- Facts
			[Fact]
			public void Should_Load_All_Rules_From_Type_Cache()
			{
				// --- Arrange
				var person = new Person()
				{
					Name = "Dane O'Connor",
					NickName = "Deeno",
					Awesomeness = 10
				};

				var fakeValueRules = new List<PropertyValueRule>();
				fakeValueRules.Add(new PropertyValueRule(new AlwaysPassValueValidator()) { PropertyName = "Name", RuleSet = "Set1" });
				fakeValueRules.Add(new PropertyValueRule(new AlwaysPassValueValidator()) { PropertyName = "NickName", RuleSet = "Set1" });
				fakeValueRules.Add(new PropertyValueRule(new AlwaysPassValueValidator()) { PropertyName = "Awesomeness", RuleSet = "Set2" });

				var mockRepository = MockRepository.GenerateMock<IPropertyRuleRepository>();
				mockRepository
					.Expect(x => x.GetPropertyValueRules())
					.Return(fakeValueRules);

				// --- Act
				var validationManager = new ValidationManager(typeof(Person).TypeHandle);

				// --- Assert
				Assert.True(validationManager.RulesCount == 3, "An incorrect number of rules were loaded");
			}

			[Fact]
			public void Should_Load_Only_Rules_In_Set_If_One_Is_Specified()
			{
				// --- Arrange
				var person = new Person()
				{
					Name = "Dane O'Connor",
					NickName = "Deeno",
					Awesomeness = 10
				};

				var fakeValueRules = new List<PropertyValueRule>();
				fakeValueRules.Add(new PropertyValueRule(new AlwaysPassValueValidator()) { PropertyName = "Name", RuleSet = "Set1" });
				fakeValueRules.Add(new PropertyValueRule(new AlwaysPassValueValidator()) { PropertyName = "NickName", RuleSet = "Set1" });
				fakeValueRules.Add(new PropertyValueRule(new AlwaysPassValueValidator()) { PropertyName = "Awesomeness", RuleSet = "Set2" });

				var mockRepository = MockRepository.GenerateMock<IPropertyRuleRepository>();
				mockRepository
					.Expect(x => x.GetPropertyValueRules())
					.Return(fakeValueRules);
				mockRepository
					.Expect(x => x.GetPropertyStateRules())
					.Return(new List<PropertyStateRule>());

				// --- Act
				var validationManager = new ValidationManager(typeof(Person).TypeHandle);

				// --- Assert
				Assert.True(validationManager.RulesCount == 2, "An incorrect number of rules were loaded");
			}

			[Fact]
			public void Should_Fill_PropertyNames_With_All_Managed_Types_Property_Names()
			{
				var person = new Person();
				// -- Arrange
				var mockRepository = MockRepository.GenerateMock<IPropertyRuleRepository>();
				mockRepository
					.Expect(x => x.GetPropertyValueRules())
					.Return(new List<PropertyValueRule>());
				mockRepository
					.Expect(x => x.GetPropertyStateRules())
					.Return(new List<PropertyStateRule>());

				// --- Act
				var validationManager = new ValidationManager(typeof(Person).TypeHandle);

				// --- Assert
				const string MissingPropertyFormat = "The property '{0}' is validation supported but was missing";
				Assert.True(validationManager.ManagedPropertyNames.Length == 3, "An incorrect number of property names were added");
				Assert.True(validationManager.ManagedPropertyNames.Contains("Name"), string.Format(MissingPropertyFormat, "Name"));
				Assert.True(validationManager.ManagedPropertyNames.Contains("NickName"), string.Format(MissingPropertyFormat, "NickName"));
				Assert.True(validationManager.ManagedPropertyNames.Contains("Awesomeness"), string.Format(MissingPropertyFormat, "Awesomeness"));
			}

		}

		public class Validate
		{
			[Fact]
			public void Should_Update_Errors_For_All_Invalid_Properties()
			{
				// --- Arrange
				var person = new Person()
				{
					Name = "Dane O'Connor",
					NickName = "Deeno",
					Awesomeness = 10
				};
				
				var fakeValueRules = new List<PropertyValueRule>(){
					new PropertyValueRule(new AlwaysPassValueValidator()) { PropertyName = "Name", RuleSet = "Set1" },
					new PropertyValueRule(new AlwaysFailValueValidator()) { PropertyName = "NickName", RuleSet = "Set1" },
					new PropertyValueRule(new AlwaysFailValueValidator()) { PropertyName = "Awesomeness", RuleSet = "Set2" }
					};
				var fakeStateRules = new List<PropertyStateRule>(){
					new PropertyStateRule(new AlwaysFailStateValidator()) { PropertyName = "Name" },
					new PropertyStateRule(new AlwaysPassStateValidator()) { PropertyName = "Name" },
					new PropertyStateRule(new AlwaysFailStateValidator()) { PropertyName = "Awesomeness" }
					};

				var mockRepository = MockRepository.GenerateMock<IPropertyRuleRepository>();

				mockRepository
					.Expect(x => x.GetPropertyValueRules())
					.Return(fakeValueRules);

				mockRepository
					.Expect(x => x.GetPropertyStateRules())
					.Return(fakeStateRules);

				// --- Act
				var validationManager = new ValidationManager(typeof(Person).TypeHandle);
				validationManager.Validate();

				// --- Assert
				Assert.True(validationManager.GetErrors().Count == 4, "An incorrect number of errors were present after validate was called");
				Assert.True(validationManager.GetErrors("Name").Count == 1);
				Assert.True(validationManager.GetErrors("NickName").Count == 1);
				Assert.True(validationManager.GetErrors("Awesomeness").Count == 2);

			}
		}

		public class GetErrors
		{
			[Fact]
			public void Should_Update_Errors_For_All_Invalid_Properties()
			{

			}
		}

	}
}
